package com.zaicheng.cloud.netty.client;
/**
 @author zaicheng
 @version 1.0
 @date 2022-04-19
 @email zzc15847256473@163.com
 */

import com.zaicheng.cloud.Client;
import com.zaicheng.cloud.netty.RpcRequest;
import com.zaicheng.cloud.netty.RpcResponse;
import com.zaicheng.cloud.netty.protocol.*;
import com.zaicheng.cloud.remotecall.Target;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import org.springframework.stereotype.Service;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class NettyClient implements Client{

    private  static ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    private  NettyClientHandler clientHandler;

    private  Response  response;

//    public NettyClient() {
//        new Thread(this).start();
//    }

    // 启动netty客户端
    public  void  startClient(String  host,int port){
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.AUTO_READ,true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            pipeline.addLast(new ProtoStuffDecoder(MessageContext.class));
                            pipeline.addLast(new ProtoStuffEncoder());
                            pipeline.addLast(clientHandler);
                        }
                    });

            System.out.println("Netty client start...");
            ChannelFuture cf = bootstrap.connect(host, port).await();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public RpcResponse execute(RpcRequest request, RpcRequest.Options options) {
        return null;
    }

    public  void  initClientHandler(){
        clientHandler = new NettyClientHandler();
    }

    @Override
    public <T>T execute(Target target, Method method, Object... args) throws ExecutionException, InterruptedException {
        // 获取服务列表

        // 负载均衡,选择一台服务调用

        if (clientHandler == null){
            initClientHandler();
            startClient("127.0.0.1",7002);
        }
        // 设置入参
        Request request = new Request();
        request.setParameterTypes(method.getParameterTypes());
        request.setClazz(target.type());
        request.setMethodName(method.getName());
        request.setArgs(args);

        MessageContext messageContext = new MessageContext(String.valueOf(new Random().nextInt(9999)),true,request);

        System.out.println("目标方法入参值："+request.getArgs());
        // 写数据到服务端
        clientHandler.setParam(messageContext);

        return (T) executorService.submit(clientHandler).get();
    }
}
